package server;

import interfaces.Product;
import interfaces.ProductList;

import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import javax.rmi.PortableRemoteObject;

public class ProductListImpl extends PortableRemoteObject implements ProductList {
	private HashMap<String, Product> productList = null;
	private ReadWriteLock rwlock = null;

	/**
	 * Constructor
	 * 
	 * @throws RemoteException
	 */
	public ProductListImpl() throws RemoteException {
		super();
		
		productList = new HashMap<String, Product>();
		rwlock = new ReentrantReadWriteLock();
	}

	/**
	 * Adds a Product to the product list
	 * 
	 * @param name		Product name
	 * @param product
	 */
	public void add( ProductImpl product ) {
		Lock wlock = rwlock.writeLock();
		wlock.lock();

		try {
			productList.put( product.getName(), (Product)product );
		} finally {
			wlock.unlock();
		}
	}
	
	/**
	 * Returns a Product by the specified name
	 * 
	 * @param name	Product name
	 * @return
	 * @throws RemoteException
	 */
	public Product get( String name ) {
		Lock rlock = rwlock.readLock();
		rlock.lock();
		
		try {
			return productList.get( name );
		}finally {
			rlock.unlock();
		}
	}

	/**
	 * Returns the entire Product list
	 * 
	 * @return
	 * @throws RemoteException
	 */
	public synchronized ArrayList<Product> getProductList()
	{
		Lock rlock = rwlock.readLock();
		rlock.lock();

		try {
			ArrayList<Product> tempProducts = new ArrayList<Product>();
			for( Product product: productList.values() ) {
				tempProducts.add( product );
			}
			
			return tempProducts;
		} finally {
			rlock.unlock();
		}

	}

	/**
	 * Returns a Product list, filtered by category
	 * 
	 * @param categoryId	Id of category to filter by
	 * @return				Product list
	 * @throws RemoteException
	 */
	public synchronized ArrayList<Product> getProductListByCategory( int categoryId ) {
		Lock rlock = rwlock.readLock();
		rlock.lock();

		try {
			ArrayList<Product> tempProductList = new ArrayList<Product>();
			for( Product product : productList.values() ) {
				try {
					if( product.getCategory().getId() == categoryId ) {
						tempProductList.add( product );
					}
				} catch( Exception e ) {
					e.printStackTrace();
				}
				
			}
			
			return tempProductList;
		} finally {
			rlock.unlock();
		}
	}
	
	/**
	 * Returns the Product by the specified name
	 * 
	 * @param name	Product name
	 * @return
	 * @throws RemoteException
	 */
	public Product getProduct( String name ) {
		return productList.get( name );
	}
}
